Canvas 简单实现脏区重绘
主要使用的 API 有 getImageData(),putImageData(), drawImage()
改进的流程图

选择框的思考与思路
转载自 Canvas脏矩形应用之截图 演示效果 https://codepen.io/joeoeoe/pen/JjPKEOG

其实截图功能非常简单,如下流程图:

如何进行截图比较简单,拖拽矩形时记录位置及长宽(即 rubberBandRectangle),在 mouseup 时通过 drawImage() 及 rubberBandRectangle 记录进行截图
但是,仅仅只是按照此流程图的话,用户体验会很不好,比如没有绘制矩形框标识选中区域 所以,我们一个截图应用至少应该拥有矩形框标识选中区域,而矩形框也是绘制在 Canvas 画布上,会影响对原图的截取,所以具体至 Canvas 绘图中流程图应该如下:

如果在鼠标移动过程中没有排除矩形框重绘,就会出现下面这种情况:

综上,我们有两个问题:
- 如何进行截图
- 如何重绘排除矩形干扰
如何重绘排除矩形干扰
这里我们引出脏矩形的概念
所谓脏矩形技术,就是哪里脏了,就(仅仅)把脏了的那块区域重绘。而不是每次直接性的重绘。
这里写出两种思路,第一种是 mousemove 时不断调用 getImageData(),通过 putImageData() 修复及去除矩形痕迹,第二种是 mousedown 时记录 Canvas 原图, mousemove 时通过对原图截取,进行局部重绘
《HTML5 Canvas核心技术》书中仅把第二种思路归为脏矩形技术,但在查阅相关定义之后,脏矩形更多可理解为局部重绘,所以我认为两种思路都是对脏矩形的应用。
由于 getImageData() 较慢,第二种思路的效率高于第一种;
方式一:不断调用 getImageData()
在 mousemove 阶段,我们不断执行如下(伪)代码
//去除局部的矩形痕迹
if (imageData !== null) {
context.putImageData(imageData,
rubberBandRectangle.left,
rubberBandRectangle.top);
}
......
//记录局部图像
imageData = context.getImageData(rubberBandRectangle.left,
rubberBandRectangle.top,
rubberBandRectangle.width,
rubberBandRectangle.height);
......
方式二:通过原图截取进行局部重绘
mousedown 阶段,记录原图(部分代码):
imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
接着在 mousemove 阶段,选取 imageData 局部,进行 canvas 上的局部重绘
ctx.putImageData(imageData, 0, 0,
rubberBandRectangle.left,
rubberBandRectangle.top,
rubberBandRectangle.width ,
rubberBandRectangle.height);